// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef WINDOW_MANAGER_WINDOW_MANAGER_H_
#define WINDOW_MANAGER_WINDOW_MANAGER_H_

#include <map>
#include <set>
#include <string>
#include <tr1/memory>
#include <utility>
#include <vector>

extern "C" {
// TODO: Move the event-handling methods (all private) into a separate
// header so that these includes can be removed.
#include <X11/extensions/shape.h>
#include <X11/extensions/sync.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrandr.h>
#include <X11/Xlib.h>
}

#include <gtest/gtest_prod.h>  // for FRIEND_TEST() macro

#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h"
#include "base/time.h"
#include "cros/chromeos_wm_ipc_enums.h"
#include "window_manager/atom_cache.h"  // for Atom enum
#include "window_manager/compositor/compositor.h"
#include "window_manager/panels/panel_manager.h"
#include "window_manager/wm_ipc.h"
#include "window_manager/x11/x_connection.h"
#include "window_manager/x11/x_types.h"

class MetricsLibrary;  // from metrics/metrics_library.h

namespace window_manager {

class ChromeWatchdog;
class DBusInterface;
class EventConsumer;
class EventLoop;
class FocusManager;
class KeyBindings;
class KeyBindingsActionRegistrar;
class KeyBindingsGroup;
class LayoutManager2;
class LoginController;
class ModalityHandler;
class ScreenLockerHandler;
class StackingManager;
class Window;
class WmIpc;
template<class T> class Stacker;

class WindowManager : public PanelManagerAreaChangeListener,
                      public CompositionChangeListener {
 public:
  // Visibility groups that actors can be added to.
  // See Compositor::SetActiveVisibilityGroups().
  enum VisibilityGroups {
    VISIBILITY_GROUP_SCREEN_LOCKER = 1,
    VISIBILITY_GROUP_SESSION_ENDING = 2,
    VISIBILITY_GROUP_BLANK = 3
  };

  // RAII-type object returned by CreateScopedCompositingRequest() that calls
  // IncrementCompositingRequests() in its constructor and
  // DecrementCompositingRequests() in its destructor.
  class ScopedCompositingRequest {
   public:
    explicit ScopedCompositingRequest(WindowManager* wm);
    ~ScopedCompositingRequest();

   private:
    WindowManager* wm_;  // not owned
    DISALLOW_COPY_AND_ASSIGN(ScopedCompositingRequest);
  };

  WindowManager(EventLoop* event_loop,
                XConnection* xconn,
                Compositor* compositor,
                DBusInterface* dbus);
  virtual ~WindowManager();

  void set_initialize_logging(bool should_init) {
    initialize_logging_ = should_init;
  }

  EventLoop* event_loop() { return event_loop_; }
  XConnection* xconn() { return xconn_; }
  Compositor* compositor() { return compositor_; }
  DBusInterface* dbus() { return dbus_; }
  StackingManager* stacking_manager() { return stacking_manager_.get(); }
  FocusManager* focus_manager() { return focus_manager_.get(); }
  ModalityHandler* modality_handler() { return modality_handler_.get(); }

  XWindow root() const { return root_; }
  const Rect& root_bounds() const { return root_bounds_; }
  Size root_size() const { return root_bounds_.size(); }
  int root_depth() const { return root_depth_; }
  int width() const { return root_bounds_.width; }
  int height() const { return root_bounds_.height; }

  const Stacker<XWindow>& stacked_xids() const {
    return *(stacked_xids_.get());
  }

  Compositor::StageActor* stage() { return stage_; }

  XWindow wm_xid() const { return wm_xid_; }
  XWindow active_window_xid() const { return active_window_xid_; }

  KeyBindings* key_bindings() { return key_bindings_.get(); }
  WmIpc* wm_ipc() { return wm_ipc_.get(); }
  int wm_ipc_version() const { return wm_ipc_version_; }

  bool logged_in() const { return logged_in_; }
  bool damage_debugging_enabled() const { return damage_debugging_enabled_; }

  // Get the title for the window that we create to take ownership of management
  // selections.  This is also used to name our log files.
  static const char* GetWmName() { return "chromeos-wm"; }

  // Begin PanelManagerAreaChangeListener implementation.
  virtual void HandlePanelManagerAreaChange();
  // End PanelManagerAreaChangeListener implementation.

  // Begin CompositionChangeListener implementation.
  // This method is called by the compositor while it's drawing, and is the
  // point at which we disable or enable compositing depending on whether
  // there's a single actor covering the entire screen or not.
  virtual void HandleTopFullscreenActorChange(
      const Compositor::TexturePixmapActor* top_fullscreen_actor);
  // End CompositionChangeListener implementation.

  // Perform initial setup.  This must be called immediately after the
  // WindowManager object is created.
  bool Init();

  // Handle notification from Chrome that the logged-in state has changed.
  // |initial| is true when this method is invoked by Init() and false when
  // it is invoked later in response to a property change.
  void SetLoggedInState(bool logged_in, bool initial);

  // Process all pending events from |x_conn_|, invoking HandleEvent() for each.
  void ProcessPendingEvents();

  // Handle an event from the X server.
  void HandleEvent(XEvent* event);

  // Create a new X window for receiving input.
  XWindow CreateInputWindow(const Rect& bounds, int event_mask);

  // Move and resize the passed-in window.
  // TODO: This isn't limited to input windows.
  bool ConfigureInputWindow(XWindow xid, const Rect& bounds);

  // Get the X server's ID corresponding to the passed-in atom (the Atom
  // enum is defined in atom_cache.h).
  XAtom GetXAtom(Atom atom);

  // Get the name for an atom from the X server.
  const std::string& GetXAtomName(XAtom xatom);

  // Get the current time from the server.  This can be useful for e.g.
  // getting a timestamp to pass to XSetInputFocus() when triggered by an
  // event that doesn't contain a timestamp.
  XTime GetCurrentTimeFromServer();

  // Look up a window in |client_windows_|.  The first version returns NULL
  // if the window doesn't exist, while the second crashes.
  Window* GetWindow(XWindow xid);
  Window* GetWindowOrDie(XWindow xid);

  Window* GetWindowOwningActor(const Compositor::TexturePixmapActor& actor);

  // Focus a window.  Convenience method that just calls
  // focus_manager_->FocusWindow().
  void FocusWindow(Window* win, XTime timestamp);

  // Does a modal window currently have the focus?
  bool IsModalWindowFocused() const;

  // Do something reasonable with the input focus.
  // This is intended to be called by EventConsumers when they give up the
  // focus and aren't sure what to do with it.
  void TakeFocus(XTime timestamp);

  // Set the _NET_ACTIVE_WINDOW property, which contains the ID of the
  // currently-active window (in our case, this is the toplevel window or
  // panel window that has the focus).
  bool SetActiveWindowProperty(XWindow xid);

  // Set the WM_NAME and NET_WM_NAME properties on a window.
  bool SetNamePropertiesForXid(XWindow xid, const std::string& name);

  // Update the _CHROME_VIDEO_TIME property on the root window, which
  // contains the last time that we believed a video was playing in a
  // window.  Note that updates may be rate-limited (see
  // kVideoTimePropertyUpdateSec).  Returns false if we attempted to set
  // the property but failed and true otherwise.
  bool SetVideoTimeProperty(time_t video_time);

  // Handle notification from a window that a new pixmap has been fetched.
  // We notify all of the event consumers that are interested in this
  // window.
  void HandleWindowPixmapFetch(Window* win);

  // Register an event consumer as being interested in non-property-change
  // events on a particular window.
  void RegisterEventConsumerForWindowEvents(
      XWindow xid, EventConsumer* event_consumer);
  void UnregisterEventConsumerForWindowEvents(
      XWindow xid, EventConsumer* event_consumer);

  // Register an event consumer as a listener for changes of a particular
  // property on a particular window.  The consumer's
  // HandleWindowPropertyChange() method will be invoked whenever we
  // receive notification that the property has been changed (after we have
  // already handled the change).
  void RegisterEventConsumerForPropertyChanges(
      XWindow xid, XAtom xatom, EventConsumer* event_consumer);
  void UnregisterEventConsumerForPropertyChanges(
      XWindow xid, XAtom xatom, EventConsumer* event_consumer);

  // Register an event consumer as being interested in a particular type of
  // WmIpc message from Chrome.  The consumer's HandleChromeMessage()
  // method will be passed all messages of this type.
  void RegisterEventConsumerForChromeMessages(
      chromeos::WmIpcMessageType message_type, EventConsumer* event_consumer);
  void UnregisterEventConsumerForChromeMessages(
      chromeos::WmIpcMessageType message_type, EventConsumer* event_consumer);

  // Register an event consumer's interest in taking ownership of a Window
  // object after the underlying X window has been destroyed.  The
  // registration will automatically be removed after the DestroyNotify
  // event, but UnregisterEventConsumerForDestroyedWindow() can be called
  // before the window is deleted to unregister interest (e.g. if the
  // event consumer itself is getting deleted).
  void RegisterEventConsumerForDestroyedWindow(
      XWindow xid, EventConsumer* event_consumer);
  void UnregisterEventConsumerForDestroyedWindow(
      XWindow xid, EventConsumer* event_consumer);

  // Register or unregister a mapping in |sync_alarms_to_windows_| between
  // a Sync extension alarm and the window that created it.
  void RegisterSyncAlarm(XID alarm_id, Window* win);
  void UnregisterSyncAlarm(XID alarm_id);

  bool client_window_debugging_enabled() const {
    return !client_window_debugging_actors_.empty();
  }

  // Callback to show or hide debugging information about client windows.
  void ToggleClientWindowDebugging();

  // Callback to toggle visualization of damage events.
  void ToggleDamageDebugging();

  // Callback to toggle profiler states.
  void ToggleProfiler();

  // Function to update client window debugging info.  Called from the
  // layout manager.
  void UpdateClientWindowDebugging();

  // Get rid of the actor that we display as a background during startup.
  void DropStartupBackground();

  // Get the total number of "real" windows.  Specifically, this is the
  // number of toplevel windows plus the number of panels.
  int GetNumWindows() const;

  // Reset |login_controller_| to NULL.  The login controller itself calls
  // this once the user has logged in and we've seen the first Chrome
  // window come up.  Note that this actually posts
  // DestroyLoginControllerInternal() to the event loop; we're probably
  // getting called in response to an X event, so we don't want to be
  // messing around with the list of event consumers.
  void DestroyLoginController();

  // Send a user action to Chrome so it can send it to UMA.
  // Does nothing if metrics reporting is disabled.
  void ReportUserAction(const std::string& action);

  // Send a histogram sample to Chrome so it can send it to UMA.
  // See metrics_library.h in metrics.git for more details.
  // Does nothing if metrics reporting is disabled.
  void ReportHistogramSample(const std::string& histogram_name,
                             int sample,
                             int min_value,
                             int max_value,
                             int num_buckets);

  // Increment or decrement a counter tracking compositing requests.  When it's
  // greater than zero, we force compositing.  If we're not already compositing,
  // IncrementCompositingRequests() will force us to draw a composited frame
  // before returning.
  void IncrementCompositingRequests();
  void DecrementCompositingRequests();

  // Create and return a new ScopedCompositingRequest object.  The caller
  // should stick it in a scoped_ptr that goes out of scope at the point where
  // the request should be withdrawn.
  ScopedCompositingRequest* CreateScopedCompositingRequest();

 private:
  friend class BasicWindowManagerTest;
  friend class LayoutManager2Test;        // uses |layout_manager_|
  friend class LoginControllerTest;       // uses |login_controller_|
  friend class ModalityHandlerTest;       // uses |modality_handler_|
  friend class PanelTest;                 // uses |panel_manager_|
  friend class PanelBarTest;              // uses |panel_manager_|
  friend class PanelDockTest;             // uses |panel_manager_|
  friend class PanelManagerTest;          // uses |panel_manager_|
  friend class ScreenLockerHandlerTest;   // uses |screen_locker_handler_|
  FRIEND_TEST(ChromeWatchdogTest, Basic);
  FRIEND_TEST(PanelBarTest, ModalDimming);
  FRIEND_TEST(WindowTest, TransientFor);  // uses TrackWindow()
  FRIEND_TEST(WindowManagerTest, RegisterExistence);
  FRIEND_TEST(WindowManagerTest, EventConsumer);
  FRIEND_TEST(WindowManagerTest, ResizeScreen);
  FRIEND_TEST(WindowManagerTest, KeepPanelsAfterRestart);
  FRIEND_TEST(WindowManagerTest, LoggedIn);
  FRIEND_TEST(WindowManagerTest, ConfigureBackground);
  FRIEND_TEST(WindowManagerTest, VideoTimeProperty);
  FRIEND_TEST(WindowManagerTest, HandleTopFullscreenActorChange);
  FRIEND_TEST(WindowManagerTest, ForceCompositing);
  FRIEND_TEST(WindowManagerTest, ResizeScreenWhileCompositing);

  typedef std::map<XWindow, std::set<EventConsumer*> > WindowEventConsumerMap;
  typedef std::map<std::pair<XWindow, XAtom>, std::set<EventConsumer*> >
      PropertyChangeEventConsumerMap;
  typedef std::map<chromeos::WmIpcMessageType, std::set<EventConsumer*> >
      ChromeMessageEventConsumerMap;

  // Minimum number of seconds between updates to the
  // _CHROME_VIDEO_TIME property on the root window.
  static const int kVideoTimePropertyUpdateSec;

  // Is this one of our internally-created windows?
  bool IsInternalWindow(XWindow xid) {
    return (xid == stage_xid_ || xid == overlay_xid_ || xid == wm_xid_);
  }

  // Are we in the process of shutting down or signing out?
  bool IsSessionEnding() const;

  // Get a manager selection as described in ICCCM section 2.8.  |atom| is
  // the selection to take, |manager_win| is the window acquiring the
  // selection, and |timestamp| is the current time.
  bool GetManagerSelection(
      XAtom atom, XWindow manager_win, XTime timestamp);

  // Tell the previous window and compositing managers to exit and register
  // ourselves as the new managers.
  bool RegisterExistence();

  // Set various one-time/unchanging properties on the root window as
  // specified in the Extended Window Manager Hints.
  bool SetEwmhGeneralProperties();

  // Set EWMH properties on the root window relating to the current screen size:
  // _NET_DESKTOP_GEOMETRY, _NET_DESKTOP_VIEWPORT, and _NET_WORKAREA (by way of
  // calling SetEwmhWorkareaProperty()).
  bool SetEwmhSizeProperties();

  // Set the _NET_WORKAREA property on the root window to the screen area
  // minus space used by panel docks.
  bool SetEwmhWorkareaProperty();

  // Register all of our key bindings.  Called by Init().
  void RegisterKeyBindings();

  // Query the X server for all toplevel windows and start tracking (and
  // possibly managing) them.
  bool ManageExistingWindows();

  // Start tracking this window (more specifically, create a Window object
  // for it and register it in |client_windows_|).  Returns NULL for
  // windows that we specifically shouldn't track (e.g. the compositor's
  // stage or the compositing overlay window).
  Window* TrackWindow(XWindow xid, bool override_redirect,
                      XConnection::WindowGeometry& geometry);

  // Handle a window getting mapped.  This is primarily used by
  // HandleMapNotify(), but is abstracted out into a separate method so
  // that ManageExistingWindows() can also use it to handle windows that
  // were already mapped when the WM started.
  void HandleMappedWindow(Window* win);

  // Handle a window getting mapped.  This is primarily used by
  // HandleUnmapNotify(), but is abstracted out into a separate method so we can
  // call it if we see a DestroyNotify event about a still-mapped window (which
  // doesn't seem like it should ever happen, but see http://crosbug.com/13792).
  void HandleUnmappedWindow(Window* win);

  // Handle the screen being resized.
  void HandleScreenResize(const Size& new_size);

  // Set the WM_STATE property on a window.  Per ICCCM 4.1.3.1, |state| can
  // be 0 (WithdrawnState), 1 (NormalState), or 3 (IconicState).  Per
  // 4.1.4, IconicState means that the toplevel window isn't viewable, so
  // we should use NormalState even when drawing a scaled-down version of
  // the window.
  bool SetWmStateProperty(XWindow xid, int state);

  // Update the _NET_CLIENT_LIST and _NET_CLIENT_LIST_STACKING properties
  // on the root window (as described in EWMH).
  bool UpdateClientListProperty();
  bool UpdateClientListStackingProperty();

  // Handlers for various X events.
  void HandleButtonPress(const XButtonEvent& e);
  void HandleButtonRelease(const XButtonEvent& e);
  void HandleClientMessage(const XClientMessageEvent& e);
  void HandleConfigureNotify(const XConfigureEvent& e);
  void HandleConfigureRequest(const XConfigureRequestEvent& e);
  void HandleCreateNotify(const XCreateWindowEvent& e);
  void HandleDamageNotify(const XDamageNotifyEvent& e);
  void HandleDestroyNotify(const XDestroyWindowEvent& e);
  void HandleEnterNotify(const XEnterWindowEvent& e);
  void HandleKeyPress(const XKeyEvent& e);
  void HandleKeyRelease(const XKeyEvent& e);
  void HandleLeaveNotify(const XLeaveWindowEvent& e);
  void HandleMapNotify(const XMapEvent& e);
  void HandleMapRequest(const XMapRequestEvent& e);
  void HandleMappingNotify(const XMappingEvent& e);
  void HandleMotionNotify(const XMotionEvent& e);
  void HandlePropertyNotify(const XPropertyEvent& e);
  void HandleReparentNotify(const XReparentEvent& e);
  void HandleRRScreenChangeNotify(const XRRScreenChangeNotifyEvent& e);
  void HandleShapeNotify(const XShapeEvent& e);
  void HandleSyncAlarmNotify(const XSyncAlarmNotifyEvent& e);
  void HandleUnmapNotify(const XUnmapEvent& e);

  // Get an arbitrary window owned by Chrome.  This can be used when
  // sending a message to Chrome, when the particular window that's used
  // doesn't matter.  Returns 0 if there aren't any Chrome windows.
  XWindow GetArbitraryChromeWindow();

  // Write a screenshot to disk.  If |select_region| is true, the
  // user will have a chance to select a region to capture.  Otherwise, the
  // entire root window will be captured.
  void TakeScreenshot(bool select_region);

  // Initialize |startup_background_| to hold a new actor that displays the
  // initial contents of the root window.  Called by Init().
  void CreateStartupBackground();

  // Helper method that creates actors and stores them in
  // |informational_actors_|.  Called by Init().
  void InitInformationalActors();

  // Callback that clears |informational_actors_|.
  void HandleDropInformationalActorsTimeout();

  // Reshape |overlay_xid_| to be transparent, redirect
  // |unredirected_fullscreen_xid_|, and tell the compositor to stop drawing.
  // We want Compositor::Draw() to finish drawing the current frame before we
  // disable compositing, so that the content on screen is refreshed.  We post
  // this method to the event loop from HandleTopFullscreenActorChange().
  void DisableCompositing();

  // Helper method posted as a task on the event loop by
  // DestroyLoginController().  This actually does the deleting.
  void DestroyLoginControllerInternal();

  // Callback invoked by |chrome_watchdog_timeout_id_| to call
  // chrome_watchdog_->SendPingToChrome().
  void PingChrome();

  EventLoop* event_loop_;   // not owned
  XConnection* xconn_;      // not owned
  Compositor* compositor_;  // not owned
  DBusInterface* dbus_;     // not owned

  XWindow root_;

  // Root window bounds and depth.
  Rect root_bounds_;
  int root_depth_;

  // Offscreen window that we just use for registering as the WM.
  XWindow wm_xid_;
  scoped_ptr<XConnection::WindowDestroyer> wm_xid_destroyer_;

  Compositor::StageActor* stage_;  // not owned

  // Window containing the compositor's stage.
  XWindow stage_xid_;

  // XComposite overlay window.
  XWindow overlay_xid_;

  // If we're started before the user has logged in, this displays the
  // initial contents of the root window.  We use this as a background.
  scoped_ptr<Compositor::TexturePixmapActor> startup_background_;

  // This is the pixmap that gets displayed by |startup_background_|.
  // We copy the root window here.
  XPixmap startup_pixmap_;

  scoped_ptr<AtomCache> atom_cache_;
  scoped_ptr<StackingManager> stacking_manager_;
  scoped_ptr<FocusManager> focus_manager_;

  // Library used to report user action metrics to Chrome.
  // NULL if --report_metrics is false.
  scoped_ptr<MetricsLibrary> metrics_library_;

  // Map from a Sync extension alarm ID to the Window object that's using
  // the alarm to support the _NET_WM_SYNC_REQUEST protocol.
  base::hash_map<XID, Window*> sync_alarms_to_windows_;

  // Windows that are being tracked.
  typedef std::map<XWindow, std::tr1::shared_ptr<Window> > WindowMap;
  WindowMap client_windows_;

  // This is a list of mapped, managed (i.e. not override-redirect) client
  // windows, in most-to-least-recently-mapped order.  Used to set EWMH's
  // _NET_CLIENT_LIST property.
  scoped_ptr<Stacker<XWindow> > mapped_xids_;

  // All immediate children of the root window (even ones that we don't
  // "track", in the sense of having Window objects for them in
  // |client_windows_|) in top-to-bottom stacking order.  EWMH's
  // _NET_CLIENT_LIST_STACKING property contains the managed (i.e. not
  // override-redirect) windows from this list.
  scoped_ptr<Stacker<XWindow> > stacked_xids_;

  // Things that consume events (e.g. LayoutManager2, PanelManager, etc.).
  std::set<EventConsumer*> event_consumers_;

  // Map from windows to event consumers that will be notified if events
  // are received.
  WindowEventConsumerMap window_event_consumers_;

  // Map from (window, atom) pairs to event consumers that will be
  // notified if the corresponding property is changed.
  PropertyChangeEventConsumerMap property_change_event_consumers_;

  // Map from Chrome message types to event consumers that will receive
  // copies of the messages.
  ChromeMessageEventConsumerMap chrome_message_event_consumers_;

  // Map from windows to the event consumer that will receive ownership of
  // the Window object when the underlying X window is destroyed.
  base::hash_map<XWindow, EventConsumer*> destroyed_window_event_consumers_;

  // Actors that are being used to show client windows' positions.
  typedef std::vector<std::tr1::shared_ptr<Compositor::Actor> > ActorVector;
  ActorVector client_window_debugging_actors_;

  // Should we flash regions of the screen in response to damage events?
  bool damage_debugging_enabled_;

  // The last window that was passed to SetActiveWindowProperty().
  XWindow active_window_xid_;

  scoped_ptr<WmIpc> wm_ipc_;
  scoped_ptr<KeyBindings> key_bindings_;
  scoped_ptr<ModalityHandler> modality_handler_;

  // These aren't initialized until the user has logged in.
  scoped_ptr<PanelManager> panel_manager_;
  scoped_ptr<LayoutManager2> layout_manager_;

  // Initialized at startup if the user isn't already logged in, and
  // deletes itself via DestroyLoginController() when the user is logged in
  // and the initial browser window is mapped.
  scoped_ptr<LoginController> login_controller_;

  scoped_ptr<ScreenLockerHandler> screen_locker_handler_;
  scoped_ptr<ChromeWatchdog> chrome_watchdog_;

  // ID for the timeout that calls QueryKeyboardState().
  int query_keyboard_state_timeout_id_;

  // Window that has currently been unredirected (in conjunction with
  // disabling compositing) as a performance optimization because it's
  // fullscreen and covering all other windows.  The value will be zero
  // whenever compositing is enabled, non-zero otherwise.
  XWindow unredirected_fullscreen_xid_;

  // Is there a task currently posted to the event loop to run
  // DisableCompositing()?
  bool disable_compositing_task_is_pending_;

  // Version of the IPC protocol that Chrome is currently using.  See
  // WM_IPC_MESSAGE_WM_NOTIFY_IPC_VERSION in libcros's
  // chromeos_wm_ipc_enums.h for details.
  int wm_ipc_version_;

  // Key binding actions that we've registered.
  scoped_ptr<KeyBindingsActionRegistrar> key_bindings_actions_;

  // Has the user logged in yet?  This affects whether some key bindings
  // are enabled or not and determines how new windows are handled.  This
  // tracks the _CHROME_LOGGED_IN property that Chrome sets on the root
  // window, but never transitions from true to false (the window manager
  // is restarted when the user logs out).
  bool logged_in_;

  // Should we initialize the logging code when we switch between logged-in
  // and logged-out mode?  This defaults to off, since we typically don't
  // want to write log files when called by tests, but main.cc sets it to
  // true.
  bool initialize_logging_;

  // Time at which we last updated the _CHROME_VIDEO_TIME property.  This is
  // a monotonically-increasing time as returned from GetMonotonicTime().
  base::TimeTicks video_property_update_time_;

  // Images that we display onscreen at startup to inform the user about
  // something (e.g. "Unaccelerated graphics", "Debug build", etc.).  Drawing
  // text would be nicer but we don't link against any graphics libraries.
  ActorVector informational_actors_;

  // ID for the timeout that calls HandleDropInformationalActorsTimeout().
  int drop_informational_actors_timeout_id_;

  // ID for the timeout that calls PingChrome().
  int chrome_watchdog_timeout_id_;

  // Number of outstanding requests to force compositing.
  int num_compositing_requests_;

  DISALLOW_COPY_AND_ASSIGN(WindowManager);
};

}  // namespace window_manager

#endif  // WINDOW_MANAGER_WINDOW_MANAGER_H_
